package org.sdnstproject.interlayer.interlayerProxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.LinkedBlockingDeque;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class InterlayerToController implements Runnable {
	private static final Logger log = LoggerFactory.getLogger(InterlayerToController.class);
	private Socket socket;
	private String controllerIP;
    private int controllerPort;
    private InputStream in;
    private OutputStream out;
    private SwitchToInterlayer other;

	public LinkedBlockingDeque<ByteBuf> msgQueue;
    public volatile boolean running = true;
    public volatile boolean isReady = false;

    
    public InterlayerToController(String controllerIP, int controllerPort) {
    	this.controllerIP = controllerIP;
    	this.controllerPort = controllerPort;
    	this.msgQueue = new LinkedBlockingDeque<>();
	}
    
    public SwitchToInterlayer getOther() {
    	return other;
    }
    
    public void setOther(SwitchToInterlayer other) {
    	this.other = other;
    }
    public void connectToController() {
        try {
			socket = new Socket(controllerIP, controllerPort);
			socket.setReuseAddress(true);
			in = socket.getInputStream();
			out = socket.getOutputStream();
			this.running =true;
		} catch (UnknownHostException e) {
			e.printStackTrace();
			running = false;
		} catch (IOException e) {
			e.printStackTrace();
			running = false;
		}
    }
    
    public void sendRawMsg(ByteBuf buf) {
        int length = buf.readableBytes();
        byte[] bytes = new byte[length];
        buf.getBytes(buf.readerIndex(), bytes);

        try {
            this.out.write(bytes, 0, length);
        } catch (IOException e) {
            e.printStackTrace();
        }

        buf.clear();
        buf.release();
    }
    
	@Override
	public void run() {
		connectToController();
		System.out.println("connectToController run...");
		byte[] recv;
        int readlen;
        try {
            while (running && !Thread.currentThread().isInterrupted()) {
            	System.out.println("connectToController recv a massage");
            	recv = new byte[8192];
                int mlen;
                int len = 0;
                if ((readlen = in.read(recv, 0, recv.length)) != -1) {
                    byte[] lenarr = {recv[2], recv[3]};
                    mlen = Integer.parseInt(javax.xml.bind.DatatypeConverter.printHexBinary(lenarr), 16);
                    ByteBuf newrecv = Unpooled.directBuffer(mlen);
                    newrecv.writeBytes(recv);
                    len = len + readlen;
                    newrecv.writerIndex(len);

                    while(mlen > len){
                        if((readlen = in.read(recv, 0, recv.length)) != -1){
                            newrecv.writeBytes(recv);
                            len = len + readlen;
                            newrecv.writerIndex(len);
                        }
                    }
                    this.other.sendRawMsg(newrecv);
                } else {
                    in.close();
                    out.close();
                    socket.close();
                    break; 
                }
            }
        } catch (Exception e) {
        	Thread.currentThread().interrupt();
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
                if (out != null)
                    out.close();
                if (socket != null)
                    socket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
		
	}
}


/*
                recv = new byte[2048];
                if ((readlen = in.read(recv, 0, recv.length)) != -1) {
                    if (readlen >= 8) {
//                    	byte[] rawMsg = new byte[readlen];
//                        System.arraycopy(recv, 0, rawMsg, 0, readlen);
                        ByteBuf newrecv = Unpooled.directBuffer(2048);
                        newrecv.writeBytes(recv);
                        msgQueue.add(newrecv);
                    }
                } else {
                	in.close();
                    out.close();
                    socket.close();
                    break; 
                }
 * 
 * */